﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Pg.BioMedics.SDR.Data;
using Pg.BioMedics.SDR.Caching;
using Pg.BioMedics.SDR.Entities;
using Pg.BioMedics.SDR.Entities.Codes;

namespace Pg.BioMedics.SDR.Data.Caching
{
    /// <summary>
    /// Data context extanding SDRDataContext functionality with distributed 
    /// cache support in the SDR domain
    /// </summary>
    public class SDRCachedDataContext : SDRDataContext
    {
        #region Fields

        private static CachedDataContextStatus status = CachedDataContextStatus.NotInitialized;

        private CachedAnnotationManager annotationManager;
        private CachedDocumentManager documentManager;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates instance of SDRDataContext. All required configuration data 
        /// are loaded from configuration file section or set as defaults 
        /// if the section does not exist.
        /// </summary>
        public SDRCachedDataContext()
            : base() { }

        /// <summary>
        /// Creates instance of SDRDataContext for given connection string.
        /// The instance support for transaction is enabled if transactions 
        /// parameter is set to true.
        /// </summary>
        /// <param name="connectionString">Connection string for SDR datbase</param>
        /// <param name="transactions">Defines if data context should operate in transaction mode</param>
        public SDRCachedDataContext(string connectionString, bool transactions)
            : base(connectionString, transactions) { }

        /// <summary>
        /// Creates instance of SDRDataContext. Instance of SDRDataContext
        /// supports or unsupports transactions depending on transactions parameter 
        /// value.
        /// </summary>
        /// <param name="transactions">Defines if data context should operate in transaction mode</param>
        public SDRCachedDataContext(bool transactions)
            : base(transactions) { }

        #endregion

        #region Static properties

        /// <summary>
        /// Gets context status
        /// </summary>
        public static CachedDataContextStatus Status
        {
            get
            {
                return status;
            }
        }

        #endregion

        #region Overriden properties

        /// <summary>
        /// Gets initialized instance of document manager supporting caching. This property 
        /// supports lazy init.
        /// </summary>
        public override DocumentManager DocumentManager
        {
            get
            {
                if (this.documentManager == null)
                    this.documentManager = new CachedDocumentManager(DataMapperStrategy);

                return this.documentManager;
            }
        }

        /// <summary>
        /// Gets initialized instance of annotation manager supporting caching. This property
        /// supports lazy init.
        /// </summary>
        public override AnnotationManager AnnotationManager
        {
            get
            {
                if (this.annotationManager == null)
                    this.annotationManager = new CachedAnnotationManager(DataMapperStrategy);

                return this.annotationManager;
            }
        }

        #endregion

        #region Static methods

        /// <summary>
        /// Loads all caches used by the SDRCahcedDataContext. This operation 
        /// blocks current thread as long as all data is loaded into the caches. 
        /// </summary>
        public static void FillCaches()
        {
            try
            {
                using (SDRDataContext dataContext = new SDRDataContext(false))
                {
                    // fill documents cache
                    foreach (Document document in dataContext.DocumentManager.GetAllDocuments())
                        SDRCacheContext.Instance.DocumentCache.Put(document);

                    // fill annotations cache
                    foreach (Annotation annotation in dataContext.AnnotationManager.GetAllAnnotations())
                        SDRCacheContext.Instance.AnnotationCache.Put(annotation);

                    // fill tokens cache
                    foreach (Token token in dataContext.AnnotationManager.GetAllTokens())
                        SDRCacheContext.Instance.TokenCache.Put(token);

                }

                status = CachedDataContextStatus.Initialized;
            }
            catch (Exception ex)
            {
                throw new DataCachingException("Couldnot fill caches", ex);
            }
        }

        /// <summary>
        /// Clears all caches realted with this context
        /// </summary>
        public static void ClearCaches()
        {
            try
            {
                SDRCacheContext.Instance.DocumentCache.Clear();
                SDRCacheContext.Instance.AnnotationCache.Clear();
                SDRCacheContext.Instance.TokenCache.Clear();

                status = CachedDataContextStatus.NotInitialized;
            }
            catch (Exception ex)
            {
                throw new DataCachingException("Couldnot clear caches", ex);
            }
        }

        #endregion
    }
}
